package team.first.movieapiv3pro.controller;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.neo4j.ogm.cypher.BooleanOperator;
import org.neo4j.ogm.cypher.ComparisonOperator;
import org.neo4j.ogm.cypher.Filter;
import org.neo4j.ogm.cypher.Filters;
import org.neo4j.ogm.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import team.first.movieapiv3pro.domain.UserNode;
import team.first.movieapiv3pro.movie.MovieNode;
import team.first.movieapiv3pro.token.Token;
import team.first.movieapiv3pro.token.TokenType;
import team.first.movieapiv3pro.util.SessionFactoryUtil;
import team.first.movieapiv3pro.vo.ApiResponse;
import team.first.movieapiv3pro.token.Token;
import team.first.movieapiv3pro.util.JWTHS256;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.Collection;
import java.util.List;

/**
 * @Author: HAPPY
 * @Project_name: project
 * @Package_name: team.first.movieapiv1pro.controller
 * @Date: 2021/12/24 15:32
 * @Description:
 */
@RestController
public class AuthorizationController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/api/v3/authorization")
    public ApiResponse<Token> authorization(HttpServletRequest request) {
        ApiResponse apiResponse = new ApiResponse();
        int flag = (int) request.getAttribute("flag");

        switch (flag) {
            case 0 -> apiResponse.setCode(401).setSuccess(false).setMessage("未认证");
            case 1 -> apiResponse.setCode(403).setSuccess(false).setMessage("认证失败");
        }

        return apiResponse;
    }

    /**
     * 2.1 POST 用户注册接口
     * @param user 要注册的用户的部分信息
     * @return 返回注册后的用户的全部信息，也就只是多个个自增id
     */
    @PostMapping("/api/v3/register")
    @ApiOperation("2.1 POST 用户注册接口")
    public ApiResponse<UserNode> register(@ApiParam("要注册的用户信息") UserNode user) {
        ApiResponse<UserNode> apiResponse = new ApiResponse<>();
        try{
            Session session = SessionFactoryUtil.getSession("team.first.movieapiv3pro.domain");
            session.save(user);

            // 一般刚注册完就会登录，所以设置一个用户的信息缓存,有效期5分钟
            stringRedisTemplate.opsForValue().set("data:movie-api-v3:user:"+user.getEmail(), JSON.toJSONString(user), Duration.ofSeconds(60 * 5));
            apiResponse.setCode(200).setSuccess(true).setMessage("注册成功").setData(user);
        } catch (Exception e){
            e.printStackTrace();
            apiResponse.setCode(500).setSuccess(false).setMessage("注册失败").setData(user);
        }
        return apiResponse;
    }

    /**
     * 用户登录（认证）接口
     *
     * @param user 登录（认证）的用户信息
     * @return 返回认证令牌
     */
    @PostMapping("/api/v3/login")
    public ApiResponse<Token> auth(UserNode user) {
        ApiResponse<Token> apiResponse = new ApiResponse<>();
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();

        Session session = SessionFactoryUtil.getSession("team.first.movieapiv3pro.domain");
        // 先看缓存里有没有该用户信息
        String userJson = operations.get("movie-api-v3:data:user:" + user.getEmail());

        UserNode cacheUser = null ;
        if (userJson != null) {
            cacheUser = JSON.parseObject(userJson, UserNode.class);
        }
        int flag = 0;
        // 判断信息是否一致
        if (cacheUser != null && user.getEmail().equals(cacheUser.getEmail()) && user.getPassword().equals(cacheUser.getPassword())) {
            // 登录成功
            flag = 1;
            user.setRoleType(cacheUser.getRoleType());
        } else { // 查询数据库
            Filters filters = new Filters();
            filters.add(new Filter("email", ComparisonOperator.EQUALS, user.getEmail()));
            Filter filter = new Filter("password", ComparisonOperator.EQUALS, user.getPassword());
            filter.setBooleanOperator(BooleanOperator.AND);
            filters.add(filter);
            Collection<UserNode> userNodes = session.loadAll(UserNode.class, filters);

            // 登录成功
            if (userNodes.size() > 0) {
                flag = 1;
                user.setRoleType(userNodes.iterator().next().getRoleType());
            }
        }

        Token token = new Token();
        // 如果登录成功, 授予令牌
        if (flag == 1) {
            String tokenValue = null;
            if (user.getRoleType() == 0) {
                token.setTokenType(TokenType.SIMPLE);
            } else {
                token.setTokenType(TokenType.VIP);
                // 普通用户token有效期30分钟、VIP用户一小时
                token.setTtl(3600);
            }
            // 利用用户邮箱生成token
            tokenValue = JWTHS256.buildJWT(user.getEmail());
            token.setTokenValue(tokenValue).setUserEmail(user.getEmail());
            // java.time.Duration.ofSeconds(long seconds)方法获取表示秒数的Duration和以纳秒为单位的调整。
            operations.set("movie-api-v3:token:" + user.getEmail(), tokenValue, Duration.ofSeconds(token.getTtl()));
            apiResponse.setData(token).setCode(200).setMessage("认证成功").setSuccess(true);
        } else {
            apiResponse.setSuccess(false).setCode(500).setMessage("认证失败");
        }

        return apiResponse;
    }
}
